#! /usr/bin/env python
# -*- coding: utf8 -*-

import time
import datetime
import json
import random
import hashlib
import math
import uuid
import HTMLParser
import calendar
import string


def decode_html(s):
    return HTMLParser.HTMLParser().unescape(s)


def serialize(data):
    try:
        return json.dumps(data, ensure_ascii=False, separators=(',', ':'))
    except Exception as e:
        # print e
        return None


def sort_serialize(data):
    '''对数据字典进行排序'''
    try:
        return json.dumps(data, sort_keys=True, indent=4, ensure_ascii=False)
    except Exception as e:
        # print e
        return None


def check_sort_serialize(data=None, msg=None):
    '''data传一个字典过来, msg传错误信息。两者不兼容！！！，有data不传msg,有msg不穿data'''
    if msg is not None and len(msg) > 0:  # 说明有错误
        return sort_serialize({"data": {}, "code": -1, "message": msg})
    elif msg is None and data is not None:
        return sort_serialize({"data": data, "code": 200, "message": "ok"})


def deserialize(data):
    try:
        return json.loads(data)
    except Exception as e:
        # print e
        return None


def random_string(length=16):
    s = ''
    for i in range(length):
        s += chr(random.randint(33, 126))
    return s


def guid():
    return str(uuid.uuid1())


def hash(plain):
    return hashlib.sha1(plain).hexdigest()


def get_ts():
    return long(time.time())


def get_ms():
    return long(time.time() * 1000)


def day2ts(day):
    """
    :param day: 2017-09-09
    :return: 时间轴
    """
    return time.mktime(time.strptime(day, '%Y-%m-%d'))


# please don't change get_day() 's time format if you want to change , notice JoshuaR
def get_day(ts=None):
    if ts is None:
        ts = get_ts()
    return time.strftime('%Y-%m-%d', time.localtime(ts))


# *****************************************

def get_week_num():
    '''
    获取今天的星期
    :return: 0~6,0->Sunday
    '''
    l_time = time.localtime()
    return int(time.strftime('%w', l_time))


def get_day_cn(ts=None):
    if ts is None:
        ts = get_ts()
    return time.strftime('%Y年%m月%d日', time.localtime(ts))


def get_interview_time(ts=None, time_format=None):
    if ts is None:
        ts = get_ts()
    if time_format == 'time':
        return time.strftime('%H:%M', time.localtime(ts))
    return time.strftime('%Y-%m-%d  %H:%M', time.localtime(ts))


def get_time(ts=None):
    if ts is None:
        ts = get_ts()
    return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ts))


def get_microtime():
    return long(time.time()) * 1000 * 1000 + datetime.datetime.now().microsecond


def get_today_zero_time():
    return day2ts(get_day())


def get_web_params(web, keys):
    params = {}

    if '' != web.data():  # collect post_body
        try:
            params.update(json.loads(web.data()))
        except Exception as e:
            print(e)
            return ({}, (-1, 'invalid data format'))
    params.update(web.input(_method='get'))  # collect url_params
    # test required keys exist
    for key in keys:
        if key not in params:
            if keys[key] is None:
                return ({}, (-1, 'param <{}> is missing'.format(key)))
            else:
                params[key] = keys[key]
    if params.has_key('user_id'):
        try:
            long(params['user_id'])
        except Exception as e:
            return ({}, (-1, 'invalid user_id = {}'.format(params['user_id'])))

    return (params, None)


def check_web_params(web, keys):
    params = {}

    if '' != web.data():  # collect post_body
        try:
            params.update(json.loads(web.data()))
        except Exception as e:
            print(e)
            return ({}, 'invalid data format')
    params.update(web.input(_method='get'))  # collect url_params
    # test required keys exist
    for key in keys:
        if key not in params:
            if keys[key] is None:
                return ({}, 'param <{}> is missing'.format(key))
            else:
                params[key] = keys[key]
    if params.has_key('user_id'):
        try:
            long(params['user_id'])
        except Exception as e:
            return ({}, 'invalid user_id = {}'.format(params['user_id']))

    return (params, None)


def verify_sig(web, keys, token):
    ''' just for dev'''
    if beichoo.DEBUG and web.input().get('debug', False):
        return True
    if web.input().has_key('sig'):
        sig_life = 300
        if web.input().has_key('sig_life'):
            sig_life = long(web.input().get('sig_life'))
            if 86400 * 30 < sig_life:
                sig_life = 86400 * 30
        if (get_ts() + sig_life) < long(web.input().get('ts')):
            return False
        # params = []
        # for key in keys:
        #     if web.input().has_key(key):
        #         params.append([key, web.input().get(key)])
        # params.sort(key = lambda x:x[0])
        params_dict = {}
        params_dict.update(web.input(_method='get'))
        del params_dict['sig']
        params = sorted(params_dict.iteritems(), key=lambda x: x[0])
        #############################################################
        for i in range(len(params)):
            params[i] = params[i][0] + '=' + params[i][1]
        plain = web.ctx.path + '?' + '&'.join(params)
        if '' != web.data():
            plain += '&' + web.data()
        plain += '&' + token
        if web.input().get('sig') == hash(plain):
            return True
    return False


def verify_sig_nolife(web, token):
    if beichoo.DEBUG and web.input().get('debug', False):
        return True
    if web.input().has_key('sig'):
        params_dict = {}
        params_dict.update(web.input(_method='get'))
        del params_dict['sig']
        params = sorted(params_dict.iteritems(), key=lambda x: x[0])
        for i in range(len(params)):
            params[i] = params[i][0] + '=' + params[i][1]
        plain = web.ctx.path + '?' + '&'.join(params)
        if '' != web.data():
            plain += '&' + web.data()
        plain += '&' + token
        if web.input().get('sig') == hash(plain):
            return True
    return False


def pagination(items, page_num, page_size):
    num_entries = len(items)
    page_max = int(math.ceil(float(num_entries) / page_size))
    if page_num < 1:
        page_num = 1
    if page_num > page_max:
        page_num = page_max
    return items[(page_num - 1) * page_size: page_num * page_size], page_num, page_max, num_entries


def get_last_month(date=None):
    if not date:
        date = get_day()
    date_list = date.split('-')
    if int(date_list[1]) == 1:
        return '{}-12'.format(int(date_list[0]) - 1)

    return '{}-{}'.format(date_list[0], str(int(date_list[1]) - 1).zfill(2))


def get_week_first_day(ts=None):
    if not ts:
        ts = get_ts()
    day = get_day(ts)
    time_list = day.split('-')
    week = calendar.weekday(int(time_list[0]), int(time_list[1]), int(time_list[2]))
    week_first_day = get_day(ts - week * 86400)
    return week_first_day


def get_week_first_timestamp(ts=None):
    a = '{} 00:00:01'.format(get_week_first_day(ts))
    s = time.mktime(time.strptime(a, '%Y-%m-%d %H:%M:%S'))
    return long(s)


def time_sleep(s=0.02):
    time.sleep(s)


def get_day_first_time(times, time_format='%Y-%m-%d'):
    timeArray = time.strptime(times, time_format)
    return long(time.mktime(timeArray))


def get_month(ts=None):
    if ts is None:
        ts = get_ts()
    return time.strftime('%Y-%m', time.localtime(ts))


def md5(src):
    m2 = hashlib.md5()
    m2.update(src)
    return m2.hexdigest()


def get_each_time(ts=None):
    if ts is None:
        ts = get_ts()
    return time.strftime('%Y-%m-%d %H', time.localtime(ts))


# date fomart YY-MM-DD
def date2ts(date):
    return time.mktime(time.strptime(date, '%Y-%m-%d'))


def time2ts(date):
    """
    :param date:
    :return: 时间轴
    """
    return time.mktime(time.strptime(date, '%Y-%m-%d %H:%M:%S'))


# 计算两天相差的天数
def d_value_day(ts, now_ts=get_ts()):
    d1 = get_day(ts)
    d2 = get_day(now_ts)
    date_list1 = d1.split('-')
    date_list2 = d2.split('-')
    d1 = datetime.datetime(int(date_list1[0]), int(date_list1[1]), int(date_list1[2]))
    d2 = datetime.datetime(int(date_list2[0]), int(date_list2[1]), int(date_list2[2]))
    return (d2 - d1).days


def is_new_channel(ctime):
    if ctime >= 1494856129:
        return True
    else:
        return False


def GenPassword(length=8, chars=string.ascii_letters + string.digits):
    return ''.join([random.choice(chars) for i in range(length)])


def transtime(time):
    return datetime.datetime.strptime(str(time), '%Y%m%d').strftime('%Y-%m-%d')


def get_weekenk_time(ctime, ts):
    '''
    :param ctime:
    :param ts:
    :return: 输出ctime所在周截止到ts 的周末时间
    '''
    saturday_start_stamp, sunday_end_time = get_weekenk_full_stamp(ctime)
    if ctime <= saturday_start_stamp:
        if ts <= sunday_end_time and ts > saturday_start_stamp:
            return ts - saturday_start_stamp
        elif ts <= saturday_start_stamp:
            return 0
        else:
            return 86400 * 2
    else:
        if ts <= sunday_end_time:
            return ts - ctime
        else:
            return sunday_end_time - ctime


def get_weekenk_full_stamp(ctime):
    '''
    :param ctime: 传入 一个时间轴
    :return:   输出 这个时间轴对应的这个周的周末的 起始时间自 和结束时间轴
    '''
    str = time.strftime("%Y-%m-%d", time.localtime(ctime))
    c_start_stamp = long(time.mktime(time.strptime(str, '%Y-%m-%d')))

    day = time.localtime(ctime).tm_wday
    if day == 5:
        return c_start_stamp, c_start_stamp + 86400 * 2
    elif day == 6:
        return c_start_stamp - 86400, c_start_stamp + 86400
    else:
        saturday_start_stamp = (5 - day) * 86400 + c_start_stamp
        return saturday_start_stamp, saturday_start_stamp + 86400 * 2


def get_month_start_end_ts():
    ts = get_ts()
    month_start_ts = 0
    month_end_ts = 0
    date = get_month(ts)
    month_start_ts = time2ts('{}-01 00:00:01'.format(date))

    date_list = date.split('-')
    if int(date_list[1]) == 12:
        year = int(date_list[0]) + 1
        month_end_ts = time2ts('{}-{}-01 00:00:00'.format(year, 01))
    else:
        month_end_ts = time2ts('{}-{}-01 00:00:00'.format(date_list[0], int(date_list[1]) + 1))

    return month_start_ts, month_end_ts - 1
